﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Linq;
using Smarly.Core;
using Smarly.Core.Database;

namespace Smarly.Bussines.Model.Account
{
	public class Login : ModelStateObject
	{
		public Login()
		{
			Roles = new List<string>();
		}

		[DatabaseValidation("EmailNotExist", "Email не зарегистрирован")]
		[Required(ErrorMessage = "Поле не заполнено")]
		[RegularExpression(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$", ErrorMessage = "Значение email не корректно")]
		public string Email { get; set; }

		[Required(ErrorMessage = "Поле не заполнено")]
		[StringLength(32, MinimumLength = 6, ErrorMessage = "Минимальная длина 6 символов")]
		[RegularExpression(@"^\w+$", ErrorMessage = "Должен содержать только цифры, латинские буквы и подчеркивание")]
		[DatabaseValidation("PasswordIncorrect", "Неправильный пароль или email")]
		public string Password { get; set; }

		internal string PasswordSalt { get; set; }

		public string HashCode { get; set; }

		public Guid UserId { get; set; }

		public List<string> Roles { get; set; }

		public bool IsIdentify { get; set; }
		public bool IsSubscriber { get; set; }

		public int PreviewCount { get; set; }

		public List<string> SpUpdates { get; set; }

		internal Login GetPasswordSalt()
		{
			SqlRepository.ExecuteProcedureReader("User_Salt",
																					 new List<SpParam>
			                                     	{
			                                     		new SpParam {Name = "@email", Type = DbType.String, Value = Email},
			                                     	},
																					 OnSqlInfoMessage,
																					 reader =>
																					 {
																						 while (reader.Read())
																						 {
																							 PasswordSalt = reader.GetString("PasswordSalt");

																						 }
																						 return this;
																					 });
			return this;
		}

		public Login ChechHash()
		{
			if (string.IsNullOrWhiteSpace(HashCode))
				return this;

			const string delimiter = "^";
			string updates = null;
			if (SpUpdates != null && SpUpdates.Count > 0)
			{
				updates = SpUpdates.Aggregate(string.Empty, (current, spUpdate) => current + (spUpdate + delimiter)).TrimEnd('^');
			}

			SqlRepository.ExecuteProcedureReader("User_CheckHashCode",
																					 new List<SpParam>
			                                     	{
			                                     		new SpParam {Name = "@email", Type = DbType.String, Value = Email},
			                                     		new SpParam {Name = "@hashCode", Type = DbType.String, Value = HashCode},
																							new SpParam {Name = "@spUpdates", Type = DbType.String, Value = updates},
																							new SpParam {Name = "@spDelimiter", Type = DbType.String, Value = delimiter},
			                                     	},
																					 OnSqlInfoMessage,
																					 reader =>
																					 {
																						 HashCode = null;
																						 Roles = new List<string>();
																						 int batchNum = 0;
																						 do
																						 {
																							 switch (batchNum)
																							 {
																								 case 0:
																									 while (reader.Read())
																									 {
																										 this.HashCode = reader.GetStringOrNull("HashCode") ?? string.Empty;
																										 this.UserId = reader.GetGuid("UserId");
																										 this.IsIdentify = reader.GetBooleanOrDefault("IsIdentify");
																									 }
																									 break;
																								 case 1:
																									 while (reader.Read())
																									 {
																										 this.Roles.Add(reader.GetString("Role"));
																									 }
																									 break;
																								 case 2:
																									 while (reader.Read())
																									 {
																										 this.IsSubscriber = reader.GetBoolean("IsSubscriber");
																									 }
																									 break;
																								 case 3:
																									 while (reader.Read())
																									 {
																										 this.PreviewCount = reader.GetInt32OrDefault("Count");
																									 }
																									 break;
																							 }
																							 batchNum++;
																						 } while (reader.NextResult());
																						 return this;
																					 });
			return this;
		}

		public Login Put()
		{
			HashCode = null;

			if (!ModelState.IsValid)
				return this;

			Login login = new Login() { Email = Email };
			login.GetPasswordSalt();


			Password pass = new Password() { PasswordString = Password, PasswordSalt = login.PasswordSalt };
			pass.EncodePassword();

			string hash = pass.PasswordHash;
			string salt = pass.PasswordSalt;

			SqlRepository.ExecuteProcedureReader("User_Login",
																					 new List<SpParam>
			                                     	{
			                                     		new SpParam {Name = "@email", Type = DbType.String, Value = Email},
			                                     		new SpParam {Name = "@passwordHash", Type = DbType.String, Value = hash},
			                                     		new SpParam {Name = "@passwordSalt", Type = DbType.String, Value = salt},
			                                     	},
																					 OnSqlInfoMessage,
																					 reader => ModelState.IsValid ? ReadPost(reader) : ReadInvalidModelStatePost(reader));
			return this;
		}

		public Login ReadPost(IDataReader reader)
		{
			while (reader.Read())
			{
				this.HashCode = reader.GetString("HashCode");
			}

			return this;
		}

		public Login ReadInvalidModelStatePost(IDataReader reader)
		{
			return this;
		}
	}
}